/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2024 INRIA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*! \file SiconosVector.hpp
 */

#ifndef __SiconosVectorIterator__
#define __SiconosVectorIterator__

#include <iterator>

template <typename V, typename T, typename TRef>
struct SiconosVectorIteratorTypeTpl {
  using iterator_category = std::forward_iterator_tag;
  using value_type = T;
  using difference_type = T;
  using pointer = T*;
  using reference = T&;

  V* v{nullptr};
  size_t p{0};
  SiconosVectorIteratorTypeTpl() = default;
  SiconosVectorIteratorTypeTpl(V& _v, size_t _p) : v(&_v), p(_p){};

  bool operator!=(const SiconosVectorIteratorTypeTpl& it) { return v != it.v || p != it.p; }
  bool operator==(const SiconosVectorIteratorTypeTpl& it) { return v == it.v && p == it.p; }

  SiconosVectorIteratorTypeTpl& operator++()
  {
    if (p < v->size()) p++;
    return *this;
  }
  SiconosVectorIteratorTypeTpl operator++(int)
  {
    SiconosVectorIteratorTypeTpl tmp(*this);
    if (p < v->size()) p++;
    return tmp;
  }

  TRef operator*() { return (*v)(p); }
};

/* Note: Derived classes here instead of typedefs only because they
 *       are easier to deal with in SWIG */

/** Specialization for non-const SiconosVector */
typedef SiconosVectorIteratorTypeTpl<SiconosVector, double, double&> SiconosVectorIteratorType;

struct SiconosVectorIterator : public SiconosVectorIteratorType {
  SiconosVectorIterator() : SiconosVectorIteratorType() {}
  SiconosVectorIterator(SiconosVectorIteratorType& it) : SiconosVectorIteratorType(*it.v, it.p)
  {
  }
  SiconosVectorIterator(SiconosVector& _v, size_t _p) : SiconosVectorIteratorType(_v, _p) {}
};

/** Specialization for const SiconosVector */
typedef SiconosVectorIteratorTypeTpl<const SiconosVector, const double, double>
    SiconosVectorConstIteratorType;

struct SiconosVectorConstIterator : public SiconosVectorConstIteratorType {
  SiconosVectorConstIterator() : SiconosVectorConstIteratorType() {}
  SiconosVectorConstIterator(SiconosVectorConstIteratorType& it)
      : SiconosVectorConstIteratorType(*it.v, it.p)
  {
  }
  SiconosVectorConstIterator(const SiconosVector& _v, size_t _p)
      : SiconosVectorConstIteratorType(_v, _p)
  {
  }
};

#endif
